package com.zlc.common.interceptor;


import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.zlc.common.common.constant.BizResponseStatus;
import com.zlc.common.common.entity.BusinessResult;
import com.zlc.common.common.exception.BadCredentialsException;
import com.zlc.common.common.exception.BusinessException;
import com.zlc.common.common.exception.InvalidTokenException;
import com.zlc.common.util.JsonHelper;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MissingPathVariableException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.sql.SQLException;
import java.sql.SQLIntegrityConstraintViolationException;
import java.util.HashMap;
import java.util.Map;

@ControllerAdvice
@RestControllerAdvice
@ResponseBody
class GlobalExceptionHandler {
    private final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    GlobalExceptionHandler() {
    }

    @ExceptionHandler({SQLException.class})
    public ResponseEntity<?> handleSQLException(Throwable e) {
        String rootCauseMessage = ExceptionUtils.getRootCauseMessage(e);
        if (StringUtils.isNotBlank(rootCauseMessage) && rootCauseMessage.contains(":")) {
            rootCauseMessage = rootCauseMessage.substring(rootCauseMessage.indexOf(":") + 1);
        }

        String status = BizResponseStatus.PARAM_VALIDATION.status();
        if (rootCauseMessage.contains("ORA-12899")) {
            this.logger.error("数据库异常：", e);
            String message = "系统检测到错误，请检查你输入的文字是否超长，请精简文字后再提交！";
            BusinessException be = new BusinessException(message, status, message);
            return this.handleBusinessExeption(be);
        } else {
            if (StringUtils.isNotBlank(rootCauseMessage) && rootCauseMessage.contains(":")) {
                rootCauseMessage = rootCauseMessage.substring(rootCauseMessage.indexOf(":") + 1);
            }

            BusinessException be = new BusinessException("数据异常: " + rootCauseMessage, status, rootCauseMessage);
            return this.handleBusinessExeption(be);
        }
    }


    @ExceptionHandler({BusinessException.class})
    @ResponseBody
    public ResponseEntity<?> handleBusinessExeption(BusinessException e) {
        return this.processBusinessExeption(e);
    }

    private ResponseEntity<?> processBusinessExeption(BusinessException e) {
        e.printStackTrace();
        this.logger.error("调用异常：", e);
        return this.response(new BusinessResult(e.getMessage(), e.getStatus(), e.getDetail()), HttpStatus.OK);
    }

    @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
    @ResponseBody
    public ResponseEntity<?> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
        return this.errorResponse(e, "不支持的请求类型（" + e.getMessage() + "）", HttpStatus.METHOD_NOT_ALLOWED);
    }

    @ExceptionHandler({InvalidTokenException.class})
    @ResponseBody
    public ResponseEntity<?> handleInvalidAuthenticationException(InvalidTokenException e) {
        return e.getMessage().contains("expired") ? this.response(new BusinessResult(e.getMessage(), BizResponseStatus.TOKEN_EXPIRED.status(), e.getMessage()), HttpStatus.OK) : this.errorResponse(e, "无效Token", HttpStatus.UNAUTHORIZED);
    }


    @ExceptionHandler({MissingServletRequestParameterException.class})
    @ResponseBody
    public ResponseEntity<?> handleMissingServletRequestParameterException(MissingServletRequestParameterException e) {
        return this.response(new BusinessResult(e.getMessage(), BizResponseStatus.PARAM_VALIDATION.status(), e.getMessage()), HttpStatus.OK);
    }

    @ExceptionHandler({MissingPathVariableException.class})
    @ResponseBody
    public ResponseEntity<?> handleMissingPathVariableException(MissingPathVariableException e) {
        return this.response(new BusinessResult(e.getMessage(), BizResponseStatus.PARAM_VALIDATION.status(), e.getMessage()), HttpStatus.OK);
    }

    @ExceptionHandler({NullPointerException.class})
    @ResponseBody
    public ResponseEntity<?> handleNullPointerException(Exception e) {
        return this.errorResponse(e, "系统异常", HttpStatus.INTERNAL_SERVER_ERROR);
    }

    @ExceptionHandler({BadCredentialsException.class})
    @ResponseBody
    public ResponseEntity<?> handleBadCredentialsException(BadCredentialsException e) {
        return this.errorResponse(e);
    }

    @ExceptionHandler({SQLIntegrityConstraintViolationException.class})
    @ResponseBody
    public ResponseEntity<?> handleConflictException(Exception e) {
        return this.errorResponse(e, "违反数据完整性约束：" + e.getMessage(), HttpStatus.CONFLICT);
    }

    @ExceptionHandler({JsonParseException.class, JsonMappingException.class})
    @ResponseBody
    public ResponseEntity<?> handleParseException(Exception e) {
        return this.errorResponse(e, "JSON解析异常", HttpStatus.BAD_REQUEST);
    }

    @ExceptionHandler({RuntimeException.class, Exception.class})
    @ResponseBody
    public ResponseEntity<?> handleRuntimeException(Exception e) {
        return this.errorResponse(e, e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
    }

    protected ResponseEntity<BusinessResult> errorResponse(Throwable throwable, String message, HttpStatus status) {
        if (null != throwable) {
            throwable.printStackTrace();
            this.logger.error("调用异常：", throwable);
            return this.response(new BusinessResult(message, String.valueOf(status.value()), message), status);
        } else {
            return this.response(null, status);
        }
    }

    protected ResponseEntity<Map> errorResponse(BadCredentialsException exception) {
        exception.printStackTrace();
        this.logger.error("调用异常：", exception);
        BusinessResult businessResult = new BusinessResult(exception.getMessage(), exception.getStatus(), exception.getMessage());
        businessResult.setCode("100");
        Map<String,Object> result = JsonHelper.jsonToMap(JsonHelper.toJson(businessResult));
        result.put("needCheckCodeFlag",exception.isNeedCheckCodeFlag());
        return this.response(result, HttpStatus.OK);
    }

    protected <T> ResponseEntity<T> response(T body, HttpStatus status) {
        HttpHeaders headers = new HttpHeaders();
        headers.set("Cache-Control", "no-store");
        headers.set("Pragma", "no-cache");
        headers.set("Content-Type", "application/json;charset=UTF-8");
        return new ResponseEntity(body, headers, status);
    }
}
